// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/metal_util/test_shader.h"

#include <CommonCrypto/CommonDigest.h>
#import <Metal/Metal.h>

#include "base/bind.h"
#include "base/feature_list.h"
#include "base/mac/scoped_dispatch_object.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/ref_counted.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "components/crash/core/common/crash_key.h"
#include "components/metal_util/device.h"

namespace metal {

namespace {

base::Feature kMetalTestShaders{"MetalTestShaders",
                                base::FEATURE_DISABLED_BY_DEFAULT};

const char* kTestShaderSource =
    ""
    "#include <metal_stdlib>\n"
    "#include <simd/simd.h>\n"
    "typedef struct {\n"
    "    float4 clipSpacePosition [[position]];\n"
    "    float4 color;\n"
    "} RasterizerData;\n"
    "\n"
    "vertex RasterizerData vertexShader(\n"
    "    uint vertexID [[vertex_id]],\n"
    "    constant vector_float2 *positions[[buffer(0)]],\n"
    "    constant vector_float4 *colors[[buffer(1)]]) {\n"
    "  RasterizerData out;\n"
    "  out.clipSpacePosition = vector_float4(0.0, 0.0, 0.0, 1.0);\n"
    "  out.clipSpacePosition.xy = positions[vertexID].xy;\n"
    "  out.color = colors[vertexID];\n"
    "  return out;\n"
    "}\n"
    "\n"
    "fragment float4 fragmentShader(RasterizerData in [[stage_in]]) {\n"
    "    return %f * in.color;\n"
    "}\n"
    "";
}  // namesspace

const size_t kTestLibSize = 0x1766;

namespace {
uint8_t kTestLibData[] = {
    0x4d, 0x54, 0x4c, 0x42, 0x01, 0x80, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x66, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x15, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00,
    0x4e, 0x41, 0x4d, 0x45, 0x0d, 0x00, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78,
    0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x00, 0x54, 0x59, 0x50, 0x45, 0x01,
    0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x20, 0x00, 0xea, 0x53, 0xd8, 0xad,
    0xe9, 0x9f, 0x43, 0x22, 0x4b, 0x14, 0xd8, 0xeb, 0x05, 0x3a, 0xb8, 0x30,
    0x10, 0xfc, 0x77, 0xf9, 0x58, 0x77, 0x59, 0xad, 0xff, 0x76, 0x2f, 0x92,
    0x8e, 0x39, 0xe8, 0xeb, 0x4d, 0x44, 0x53, 0x5a, 0x08, 0x00, 0x90, 0x0b,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x46, 0x46, 0x54, 0x18, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x56, 0x45, 0x52, 0x53, 0x08, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00,
    0x01, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x84, 0x00, 0x00, 0x00, 0x4e, 0x41,
    0x4d, 0x45, 0x0f, 0x00, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74,
    0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x00, 0x54, 0x59, 0x50, 0x45, 0x01,
    0x00, 0x01, 0x48, 0x41, 0x53, 0x48, 0x20, 0x00, 0x03, 0xe2, 0x3a, 0x4c,
    0xf7, 0x70, 0x1a, 0x18, 0xe3, 0x6a, 0x5d, 0x63, 0x59, 0x7f, 0x36, 0x18,
    0xd1, 0x28, 0x2c, 0x83, 0x2a, 0x88, 0x7f, 0x29, 0xda, 0x25, 0xb5, 0x15,
    0x6b, 0x43, 0xfd, 0xce, 0x4d, 0x44, 0x53, 0x5a, 0x08, 0x00, 0x50, 0x0a,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x46, 0x46, 0x54, 0x18, 0x00,
    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x90, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x56, 0x45, 0x52, 0x53, 0x08, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00,
    0x01, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x45, 0x4e, 0x44, 0x54, 0x04, 0x00,
    0x00, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x04, 0x00, 0x00, 0x00, 0x45, 0x4e,
    0x44, 0x54, 0x04, 0x00, 0x00, 0x00, 0x45, 0x4e, 0x44, 0x54, 0x04, 0x00,
    0x00, 0x00, 0x45, 0x4e, 0x44, 0x54, 0xde, 0xc0, 0x17, 0x0b, 0x00, 0x00,
    0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x78, 0x0b, 0x00, 0x00, 0xff, 0xff,
    0xff, 0xff, 0x42, 0x43, 0xc0, 0xde, 0x35, 0x14, 0x00, 0x00, 0x03, 0x00,
    0x00, 0x00, 0x62, 0x0c, 0x30, 0x24, 0x80, 0x10, 0x05, 0xc8, 0x14, 0x00,
    0x00, 0x00, 0x21, 0x0c, 0x00, 0x00, 0xa6, 0x02, 0x00, 0x00, 0x0b, 0x02,
    0x21, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81,
    0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01,
    0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10,
    0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08,
    0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46,
    0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0x04, 0x49, 0x0e, 0x90, 0x11, 0x22,
    0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21,
    0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x1b, 0xfa,
    0x25, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x03, 0x40, 0x02, 0x2a,
    0x62, 0x1c, 0xde, 0x41, 0x1e, 0xe4, 0xa1, 0x1c, 0xc6, 0x81, 0x1e, 0xd8,
    0x21, 0x1f, 0xda, 0x40, 0x1e, 0xde, 0xa1, 0x1e, 0xdc, 0x81, 0x1c, 0xca,
    0x81, 0x1c, 0xda, 0x80, 0x1c, 0xd2, 0xc1, 0x1e, 0xd2, 0x81, 0x1c, 0xca,
    0xa1, 0x0d, 0xe6, 0x21, 0x1e, 0xe4, 0x81, 0x1e, 0xda, 0xc0, 0x1c, 0xe0,
    0xa1, 0x0d, 0xda, 0x21, 0x1c, 0xe8, 0x01, 0x1d, 0x00, 0x73, 0x08, 0x07,
    0x76, 0x98, 0x87, 0x72, 0x00, 0x08, 0x72, 0x48, 0x87, 0x79, 0x08, 0x07,
    0x71, 0x60, 0x87, 0x72, 0x68, 0x03, 0x7a, 0x08, 0x87, 0x74, 0x60, 0x87,
    0x36, 0x18, 0x87, 0x70, 0x60, 0x07, 0x76, 0x98, 0x07, 0xc0, 0x1c, 0xc2,
    0x81, 0x1d, 0xe6, 0xa1, 0x1c, 0x00, 0x82, 0x1d, 0xca, 0x61, 0x1e, 0xe6,
    0xa1, 0x0d, 0xe0, 0x41, 0x1e, 0xca, 0x61, 0x1c, 0xd2, 0x61, 0x1e, 0xca,
    0xa1, 0x0d, 0xcc, 0x01, 0x1e, 0xda, 0x21, 0x1c, 0xc8, 0x01, 0x30, 0x87,
    0x70, 0x60, 0x87, 0x79, 0x28, 0x07, 0x80, 0x70, 0x87, 0x77, 0x68, 0x03,
    0x73, 0x90, 0x87, 0x70, 0x68, 0x87, 0x72, 0x68, 0x03, 0x78, 0x78, 0x87,
    0x74, 0x70, 0x07, 0x7a, 0x28, 0x07, 0x79, 0x68, 0x83, 0x72, 0x60, 0x87,
    0x74, 0x68, 0x07, 0x80, 0x1e, 0xe4, 0xa1, 0x1e, 0xca, 0x01, 0x18, 0xdc,
    0xe1, 0x1d, 0xda, 0xc0, 0x1c, 0xe4, 0x21, 0x1c, 0xda, 0xa1, 0x1c, 0xda,
    0x00, 0x1e, 0xde, 0x21, 0x1d, 0xdc, 0x81, 0x1e, 0xca, 0x41, 0x1e, 0xda,
    0xa0, 0x1c, 0xd8, 0x21, 0x1d, 0xda, 0xa1, 0x0d, 0xdc, 0xe1, 0x1d, 0xdc,
    0xa1, 0x0d, 0xd8, 0xa1, 0x1c, 0xc2, 0xc1, 0x1c, 0x00, 0xc2, 0x1d, 0xde,
    0xa1, 0x0d, 0xd2, 0xc1, 0x1d, 0xcc, 0x61, 0x1e, 0xda, 0xc0, 0x1c, 0xe0,
    0xa1, 0x0d, 0xda, 0x21, 0x1c, 0xe8, 0x01, 0x1d, 0x00, 0x7a, 0x90, 0x87,
    0x7a, 0x28, 0x07, 0x80, 0x70, 0x87, 0x77, 0x68, 0x03, 0x75, 0xa8, 0x87,
    0x76, 0x80, 0x87, 0x36, 0xa0, 0x87, 0x70, 0x10, 0x07, 0x76, 0x28, 0x87,
    0x79, 0x00, 0xcc, 0x21, 0x1c, 0xd8, 0x61, 0x1e, 0xca, 0x01, 0x20, 0xdc,
    0xe1, 0x1d, 0xda, 0xc0, 0x1d, 0xc2, 0xc1, 0x1d, 0xe6, 0xa1, 0x0d, 0xcc,
    0x01, 0x1e, 0xda, 0xa0, 0x1d, 0xc2, 0x81, 0x1e, 0xd0, 0x01, 0xa0, 0x07,
    0x79, 0xa8, 0x87, 0x72, 0x00, 0x08, 0x77, 0x78, 0x87, 0x36, 0x98, 0x87,
    0x74, 0x38, 0x07, 0x77, 0x28, 0x07, 0x72, 0x68, 0x03, 0x7d, 0x28, 0x07,
    0x79, 0x78, 0x87, 0x79, 0x68, 0x03, 0x73, 0x80, 0x87, 0x36, 0x68, 0x87,
    0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00,
    0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xe8, 0x41, 0x1e, 0xc2, 0x01, 0x1e, 0xe0,
    0x21, 0x1d, 0xdc, 0xe1, 0x1c, 0xda, 0xa0, 0x1d, 0xc2, 0x81, 0x1e, 0xd0,
    0x01, 0xa0, 0x07, 0x79, 0xa8, 0x87, 0x72, 0x00, 0x88, 0x79, 0xa0, 0x87,
    0x70, 0x18, 0x87, 0x75, 0x68, 0x03, 0x78, 0x90, 0x87, 0x77, 0xa0, 0x87,
    0x72, 0x18, 0x07, 0x7a, 0x78, 0x07, 0x79, 0x68, 0x03, 0x71, 0xa8, 0x07,
    0x73, 0x30, 0x87, 0x72, 0x90, 0x87, 0x36, 0x98, 0x87, 0x74, 0xd0, 0x87,
    0x72, 0x00, 0xf0, 0x00, 0x20, 0xe8, 0x21, 0x1c, 0xe4, 0xe1, 0x1c, 0xca,
    0x81, 0x1e, 0xda, 0xc0, 0x1c, 0xca, 0x21, 0x1c, 0xe8, 0xa1, 0x1e, 0xe4,
    0xa1, 0x1c, 0xe6, 0x01, 0x68, 0x03, 0x73, 0x80, 0x87, 0x38, 0xb0, 0x03,
    0x80, 0xa8, 0x07, 0x77, 0x98, 0x87, 0x70, 0x30, 0x87, 0x72, 0x68, 0x03,
    0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8,
    0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00, 0xa2, 0x1e, 0xe6, 0xa1, 0x1c, 0xda,
    0x60, 0x1e, 0xde, 0xc1, 0x1c, 0xe8, 0xa1, 0x0d, 0xcc, 0x81, 0x1d, 0xde,
    0x21, 0x1c, 0xe8, 0x01, 0x30, 0x87, 0x70, 0x60, 0x87, 0x79, 0x28, 0x07,
    0x60, 0x03, 0x22, 0x08, 0x40, 0x02, 0x2c, 0x40, 0xb5, 0x01, 0x19, 0x06,
    0x20, 0x01, 0x16, 0xa0, 0x02, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00,
    0x00, 0x00, 0x13, 0x86, 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20,
    0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64,
    0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1,
    0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x34,
    0x33, 0x00, 0xc3, 0x08, 0x04, 0x70, 0x95, 0x34, 0x45, 0x94, 0x30, 0xf9,
    0x2b, 0x20, 0x4d, 0x44, 0x84, 0x64, 0x44, 0xd4, 0x01, 0x13, 0x80, 0x84,
    0x88, 0x39, 0x02, 0x30, 0x18, 0x46, 0x10, 0x80, 0x41, 0x04, 0x42, 0x18,
    0x44, 0x08, 0x84, 0x42, 0xc8, 0x94, 0xd1, 0x0d, 0x04, 0xcc, 0x11, 0x80,
    0xc2, 0x30, 0x02, 0x31, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xb2,
    0x70, 0x48, 0x07, 0x79, 0xb0, 0x03, 0x3a, 0x68, 0x83, 0x70, 0x80, 0x07,
    0x78, 0x60, 0x87, 0x72, 0x68, 0x83, 0x76, 0x08, 0x87, 0x71, 0x78, 0x87,
    0x79, 0xc0, 0x87, 0x38, 0x80, 0x03, 0x37, 0x88, 0x03, 0x3a, 0x70, 0x03,
    0x38, 0xd8, 0xf0, 0x1e, 0xe5, 0xd0, 0x06, 0xf0, 0xa0, 0x07, 0x76, 0x40,
    0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x90,
    0x0e, 0x71, 0xa0, 0x07, 0x78, 0xa0, 0x07, 0x78, 0xd0, 0x06, 0xe9, 0x80,
    0x07, 0x7a, 0x80, 0x07, 0x7a, 0x80, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60,
    0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x6d, 0x90,
    0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20,
    0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0,
    0x07, 0x76, 0x40, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30,
    0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x76, 0x40,
    0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x60,
    0x0e, 0x78, 0x00, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10,
    0x07, 0x72, 0x80, 0x07, 0x6d, 0x60, 0x0f, 0x71, 0x60, 0x07, 0x7a, 0x10,
    0x07, 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x72, 0x40,
    0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60,
    0x0f, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20,
    0x07, 0x6d, 0x60, 0x0f, 0x74, 0x80, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0,
    0x07, 0x76, 0x40, 0x07, 0x6d, 0x60, 0x0f, 0x76, 0x40, 0x07, 0x7a, 0x60,
    0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x60, 0x0f, 0x79, 0x60,
    0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80,
    0x07, 0x6d, 0x60, 0x0f, 0x71, 0x20, 0x07, 0x78, 0xa0, 0x07, 0x71, 0x20,
    0x07, 0x78, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xf6, 0x10,
    0x07, 0x79, 0x20, 0x07, 0x7a, 0x20, 0x07, 0x75, 0x60, 0x07, 0x7a, 0x20,
    0x07, 0x75, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x72, 0x50, 0x07, 0x76, 0xa0,
    0x07, 0x72, 0x50, 0x07, 0x76, 0xa0, 0x07, 0x72, 0x50, 0x07, 0x76, 0xd0,
    0x06, 0xf6, 0x50, 0x07, 0x71, 0x20, 0x07, 0x7a, 0x50, 0x07, 0x71, 0x20,
    0x07, 0x7a, 0x50, 0x07, 0x71, 0x20, 0x07, 0x6d, 0x60, 0x0f, 0x71, 0x00,
    0x07, 0x72, 0x40, 0x07, 0x7a, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xa0,
    0x07, 0x71, 0x00, 0x07, 0x72, 0x40, 0x07, 0x6d, 0x60, 0x0e, 0x78, 0x00,
    0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80,
    0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30,
    0x07, 0x72, 0xa0, 0x11, 0xc2, 0x90, 0x4c, 0x45, 0x44, 0x13, 0x71, 0xb1,
    0x07, 0x30, 0x10, 0xd1, 0x90, 0x08, 0x60, 0x0e, 0x00, 0x00, 0x02, 0x00,
    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x90, 0xd8, 0x20, 0x50, 0x14, 0x55,
    0x00, 0x00, 0x20, 0x0b, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x32, 0x1e,
    0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04,
    0x43, 0x9a, 0x12, 0x28, 0x84, 0x22, 0x18, 0x01, 0x28, 0x88, 0x02, 0x21,
    0x1d, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x18, 0x00, 0x00, 0x6d, 0x00,
    0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01,
    0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78,
    0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4,
    0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c,
    0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03,
    0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70,
    0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70,
    0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec,
    0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0,
    0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d,
    0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43,
    0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0,
    0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68,
    0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28,
    0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08,
    0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee,
    0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62,
    0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c,
    0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06,
    0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43,
    0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3,
    0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3,
    0x0c, 0xc7, 0x69, 0x87, 0x70, 0x58, 0x87, 0x72, 0x70, 0x83, 0x74, 0x68,
    0x07, 0x78, 0x60, 0x87, 0x74, 0x18, 0x87, 0x74, 0xa0, 0x87, 0x19, 0xce,
    0x53, 0x0f, 0xee, 0x00, 0x0f, 0xf2, 0x50, 0x0e, 0xe4, 0x90, 0x0e, 0xe3,
    0x40, 0x0f, 0xe1, 0x20, 0x0e, 0xec, 0x50, 0x0e, 0x33, 0x20, 0x28, 0x1d,
    0xdc, 0xc1, 0x1e, 0xc2, 0x41, 0x1e, 0xd2, 0x21, 0x1c, 0xdc, 0x81, 0x1e,
    0xdc, 0xe0, 0x1c, 0xe4, 0xe1, 0x1d, 0xea, 0x01, 0x1e, 0x66, 0x18, 0x51,
    0x38, 0xb0, 0x43, 0x3a, 0x9c, 0x83, 0x3b, 0xcc, 0x50, 0x24, 0x76, 0x60,
    0x07, 0x7b, 0x68, 0x07, 0x37, 0x60, 0x87, 0x77, 0x78, 0x07, 0x78, 0x98,
    0x51, 0x4c, 0xf4, 0x90, 0x0f, 0xf0, 0x50, 0x0e, 0x33, 0x1e, 0x6a, 0x1e,
    0xca, 0x61, 0x1c, 0xe8, 0x21, 0x1d, 0xde, 0xc1, 0x1d, 0x7e, 0x01, 0x1e,
    0xe4, 0xa1, 0x1c, 0xcc, 0x21, 0x1d, 0xf0, 0x61, 0x06, 0x54, 0x85, 0x83,
    0x38, 0xcc, 0xc3, 0x3b, 0xb0, 0x43, 0x3d, 0xd0, 0x43, 0x39, 0xfc, 0xc2,
    0x3c, 0xe4, 0x43, 0x3b, 0x88, 0xc3, 0x3b, 0xb0, 0xc3, 0x8c, 0xc5, 0x0a,
    0x87, 0x79, 0x98, 0x87, 0x77, 0x18, 0x87, 0x74, 0x08, 0x07, 0x7a, 0x28,
    0x07, 0x72, 0x00, 0x00, 0x00, 0x00, 0x79, 0x20, 0x00, 0x00, 0xb4, 0x00,
    0x00, 0x00, 0x62, 0x1e, 0x48, 0x20, 0x43, 0x88, 0x0c, 0x19, 0x39, 0x19,
    0x24, 0x90, 0x91, 0x40, 0xc6, 0xc8, 0xc8, 0x68, 0x22, 0x50, 0x08, 0x14,
    0x32, 0x9e, 0x18, 0x19, 0x21, 0x47, 0xc8, 0x90, 0x51, 0xd4, 0xb0, 0xba,
    0x01, 0x00, 0xca, 0x1a, 0x14, 0x1b, 0x57, 0x06, 0x61, 0xc0, 0x44, 0x06,
    0x13, 0x45, 0x56, 0xd1, 0x10, 0x88, 0x22, 0x21, 0xd1, 0x65, 0x24, 0x06,
    0x00, 0x00, 0x77, 0x63, 0x68, 0x61, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65,
    0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x4c, 0x4c, 0x56, 0x4d, 0x20, 0x76,
    0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x39, 0x30, 0x32, 0x2e, 0x31,
    0x20, 0x28, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x66, 0x65, 0x2d, 0x39, 0x30,
    0x32, 0x2e, 0x31, 0x2e, 0x34, 0x39, 0x29, 0x4d, 0x65, 0x74, 0x61, 0x6c,
    0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e,
    0x64, 0x65, 0x6e, 0x6f, 0x72, 0x6d, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61,
    0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69,
    0x6c, 0x65, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x68,
    0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e, 0x63,
    0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0x66, 0x72, 0x61, 0x6d, 0x65,
    0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68,
    0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e,
    0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0x6e, 0x61, 0x74, 0x69,
    0x76, 0x65, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69,
    0x73, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e, 0x70, 0x6f, 0x73,
    0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x69, 0x72, 0x2e, 0x61, 0x72, 0x67,
    0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x66, 0x6c,
    0x6f, 0x61, 0x74, 0x34, 0x61, 0x69, 0x72, 0x2e, 0x61, 0x72, 0x67, 0x5f,
    0x6e, 0x61, 0x6d, 0x65, 0x63, 0x6c, 0x69, 0x70, 0x53, 0x70, 0x61, 0x63,
    0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x69, 0x72,
    0x2e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x70,
    0x75, 0x74, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x28,
    0x35, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x44, 0x76, 0x34, 0x5f, 0x66, 0x29,
    0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x65, 0x72,
    0x74, 0x65, 0x78, 0x5f, 0x69, 0x64, 0x75, 0x69, 0x6e, 0x74, 0x76, 0x65,
    0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x61, 0x69, 0x72, 0x2e, 0x62, 0x75,
    0x66, 0x66, 0x65, 0x72, 0x61, 0x69, 0x72, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
    0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x61, 0x69,
    0x72, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x61, 0x69, 0x72, 0x2e, 0x61, 0x72,
    0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x61,
    0x69, 0x72, 0x2e, 0x61, 0x72, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f,
    0x61, 0x6c, 0x69, 0x67, 0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x66, 0x6c,
    0x6f, 0x61, 0x74, 0x32, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
    0x73, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x00, 0x23, 0x08,
    0x43, 0x30, 0x82, 0x30, 0x08, 0x23, 0x08, 0xc3, 0x30, 0x82, 0x30, 0x10,
    0x23, 0x08, 0x08, 0x30, 0x82, 0x30, 0x14, 0x23, 0x08, 0x83, 0x31, 0xc3,
    0xb0, 0x05, 0xdc, 0x0c, 0x81, 0x30, 0xc3, 0xd0, 0x6d, 0xde, 0x0c, 0xc4,
    0xd0, 0x6d, 0xde, 0x0c, 0x01, 0x31, 0x43, 0x50, 0xcc, 0x10, 0x18, 0x33,
    0x04, 0xc7, 0x0c, 0x05, 0x92, 0x28, 0x0b, 0x33, 0x83, 0xd1, 0x38, 0x89,
    0xb2, 0x3c, 0x33, 0x08, 0x6a, 0xb0, 0x06, 0x33, 0x18, 0x1e, 0x94, 0x44,
    0x8b, 0x34, 0x83, 0xb3, 0x4d, 0x94, 0xb7, 0x55, 0x16, 0x18, 0x5c, 0x60,
    0x90, 0x60, 0x4b, 0x36, 0x83, 0xd3, 0x4d, 0xd4, 0xb6, 0x55, 0x56, 0x18,
    0x5c, 0x61, 0x90, 0x28, 0x8b, 0x36, 0xc3, 0xd0, 0x06, 0x6e, 0xf0, 0x06,
    0x33, 0x0c, 0x1f, 0x1b, 0xc0, 0x81, 0x8c, 0x04, 0x26, 0x28, 0x23, 0x36,
    0x36, 0xbb, 0x36, 0x97, 0xb6, 0x37, 0xb2, 0x3a, 0xb6, 0x32, 0x17, 0x33,
    0xb6, 0xb0, 0xb3, 0xb9, 0x51, 0x82, 0x30, 0x48, 0x85, 0x8d, 0xcd, 0xae,
    0xcd, 0x25, 0x8d, 0xac, 0xcc, 0x8d, 0x6e, 0x94, 0x40, 0x0c, 0x72, 0x09,
    0x4b, 0x93, 0x73, 0xb1, 0x2b, 0x93, 0x9b, 0x4b, 0x7b, 0x73, 0x1b, 0x25,
    0x18, 0x83, 0xa4, 0xc2, 0xd2, 0xe4, 0x5c, 0xd8, 0xc2, 0xdc, 0xce, 0xea,
    0xc2, 0xce, 0xca, 0xbe, 0xec, 0xca, 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 0x46,
    0x09, 0xc8, 0x20, 0xa7, 0xb0, 0x34, 0x39, 0x97, 0xb1, 0xb7, 0x36, 0xb8,
    0x34, 0xb6, 0xb2, 0xaf, 0x37, 0x38, 0xba, 0xb4, 0x37, 0xb7, 0xb9, 0x51,
    0x88, 0x32, 0x30, 0x83, 0x33, 0x40, 0x83, 0x54, 0xc2, 0xd2, 0xe4, 0x5c,
    0xec, 0xca, 0xe4, 0xe8, 0xca, 0xf0, 0x46, 0x09, 0xe0, 0x00, 0x00, 0x00,
    0x00, 0x00, 0xa9, 0x18, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x0a,
    0x72, 0x28, 0x87, 0x77, 0x80, 0x07, 0x7a, 0x58, 0x70, 0x98, 0x43, 0x3d,
    0xb8, 0xc3, 0x38, 0xb0, 0x43, 0x39, 0xd0, 0xc3, 0x82, 0xe6, 0x1c, 0xc6,
    0xa1, 0x0d, 0xe8, 0x41, 0x1e, 0xc2, 0xc1, 0x1d, 0xe6, 0x21, 0x1d, 0xe8,
    0x21, 0x1d, 0xde, 0xc1, 0x1d, 0x00, 0xd1, 0x10, 0x00, 0x00, 0x06, 0x00,
    0x00, 0x00, 0x07, 0xcc, 0x3c, 0xa4, 0x83, 0x3b, 0x9c, 0x03, 0x3b, 0x94,
    0x03, 0x3d, 0xa0, 0x83, 0x3c, 0x94, 0x43, 0x38, 0x90, 0xc3, 0x01, 0x00,
    0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x13, 0x04,
    0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x34, 0x33,
    0x00, 0xb4, 0x73, 0x10, 0x44, 0xb0, 0x2c, 0x63, 0x11, 0x44, 0x21, 0x0c,
    0x04, 0x33, 0x00, 0x23, 0x00, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf8, 0x47,
    0x31, 0x07, 0xe1, 0x38, 0x0f, 0x44, 0x32, 0x03, 0x40, 0x34, 0x03, 0x00,
    0x00, 0x00, 0xf1, 0x30, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x22, 0x47,
    0xc8, 0x90, 0x51, 0x0a, 0x84, 0x18, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x03,
    0x00, 0x00, 0x6f, 0x6d, 0x6e, 0x69, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74,
    0x20, 0x63, 0x68, 0x61, 0x72, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20,
    0x43, 0x2b, 0x2b, 0x20, 0x54, 0x42, 0x41, 0x41, 0x00, 0x00, 0x13, 0x04,
    0xe5, 0xd8, 0x10, 0xcc, 0xc1, 0x86, 0x41, 0x0e, 0xea, 0x80, 0x0e, 0x36,
    0x0c, 0x76, 0x60, 0x07, 0x74, 0x00, 0xc7, 0x68, 0x6c, 0x12, 0x98, 0x80,
    0x02, 0x22, 0x83, 0x0c, 0x01, 0xb1, 0x0c, 0x32, 0x1c, 0xc1, 0xb2, 0x43,
    0x78, 0x0a, 0x0a, 0xa2, 0xcc, 0x36, 0x24, 0x03, 0x30, 0xdb, 0x10, 0x08,
    0x41, 0x06, 0x01, 0x31, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5b, 0x06,
    0x23, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x20,
    0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, 0x0e, 0x10, 0x22, 0x84, 0x00,
    0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x0c,
    0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x12, 0x03, 0x94, 0xe8, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00,
    0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
    0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
    0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
    0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x5d, 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x03,
    0x94, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78,
    0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x39, 0x30, 0x32, 0x2e, 0x31, 0x2e,
    0x34, 0x39, 0x61, 0x69, 0x72, 0x36, 0x34, 0x2d, 0x61, 0x70, 0x70, 0x6c,
    0x65, 0x2d, 0x6d, 0x61, 0x63, 0x6f, 0x73, 0x78, 0x31, 0x30, 0x2e, 0x31,
    0x34, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0xde, 0xc0, 0x17, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
    0x00, 0x00, 0x38, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x42, 0x43,
    0xc0, 0xde, 0x35, 0x14, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x62, 0x0c,
    0x30, 0x24, 0x80, 0x10, 0x05, 0xc8, 0x14, 0x00, 0x00, 0x00, 0x21, 0x0c,
    0x00, 0x00, 0x56, 0x02, 0x00, 0x00, 0x0b, 0x02, 0x21, 0x00, 0x02, 0x00,
    0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8,
    0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05,
    0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92,
    0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32,
    0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19,
    0x32, 0x42, 0x04, 0x49, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51,
    0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18,
    0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x1b, 0xfa, 0x25, 0xf8, 0xff, 0xff,
    0xff, 0xff, 0x01, 0x80, 0x03, 0x40, 0x02, 0x28, 0x62, 0x1c, 0xde, 0x41,
    0x1e, 0xe4, 0xa1, 0x1c, 0xc6, 0x81, 0x1e, 0xd8, 0x21, 0x1f, 0xda, 0x40,
    0x1e, 0xde, 0xa1, 0x1e, 0xdc, 0x81, 0x1c, 0xca, 0x81, 0x1c, 0xda, 0x80,
    0x1c, 0xd2, 0xc1, 0x1e, 0xd2, 0x81, 0x1c, 0xca, 0xa1, 0x0d, 0xe6, 0x21,
    0x1e, 0xe4, 0x81, 0x1e, 0xda, 0xc0, 0x1c, 0xe0, 0xa1, 0x0d, 0xda, 0x21,
    0x1c, 0xe8, 0x01, 0x1d, 0x00, 0x73, 0x08, 0x07, 0x76, 0x98, 0x87, 0x72,
    0x00, 0x08, 0x72, 0x48, 0x87, 0x79, 0x08, 0x07, 0x71, 0x60, 0x87, 0x72,
    0x68, 0x03, 0x7a, 0x08, 0x87, 0x74, 0x60, 0x87, 0x36, 0x18, 0x87, 0x70,
    0x60, 0x07, 0x76, 0x98, 0x07, 0xc0, 0x1c, 0xc2, 0x81, 0x1d, 0xe6, 0xa1,
    0x1c, 0x00, 0x82, 0x1d, 0xca, 0x61, 0x1e, 0xe6, 0xa1, 0x0d, 0xe0, 0x41,
    0x1e, 0xca, 0x61, 0x1c, 0xd2, 0x61, 0x1e, 0xca, 0xa1, 0x0d, 0xcc, 0x01,
    0x1e, 0xda, 0x21, 0x1c, 0xc8, 0x01, 0x30, 0x87, 0x70, 0x60, 0x87, 0x79,
    0x28, 0x07, 0x80, 0x70, 0x87, 0x77, 0x68, 0x03, 0x73, 0x90, 0x87, 0x70,
    0x68, 0x87, 0x72, 0x68, 0x03, 0x78, 0x78, 0x87, 0x74, 0x70, 0x07, 0x7a,
    0x28, 0x07, 0x79, 0x68, 0x83, 0x72, 0x60, 0x87, 0x74, 0x68, 0x07, 0x80,
    0x1e, 0xe4, 0xa1, 0x1e, 0xca, 0x01, 0x18, 0xdc, 0xe1, 0x1d, 0xda, 0xc0,
    0x1c, 0xe4, 0x21, 0x1c, 0xda, 0xa1, 0x1c, 0xda, 0x00, 0x1e, 0xde, 0x21,
    0x1d, 0xdc, 0x81, 0x1e, 0xca, 0x41, 0x1e, 0xda, 0xa0, 0x1c, 0xd8, 0x21,
    0x1d, 0xda, 0xa1, 0x0d, 0xdc, 0xe1, 0x1d, 0xdc, 0xa1, 0x0d, 0xd8, 0xa1,
    0x1c, 0xc2, 0xc1, 0x1c, 0x00, 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xd2, 0xc1,
    0x1d, 0xcc, 0x61, 0x1e, 0xda, 0xc0, 0x1c, 0xe0, 0xa1, 0x0d, 0xda, 0x21,
    0x1c, 0xe8, 0x01, 0x1d, 0x00, 0x7a, 0x90, 0x87, 0x7a, 0x28, 0x07, 0x80,
    0x70, 0x87, 0x77, 0x68, 0x03, 0x75, 0xa8, 0x87, 0x76, 0x80, 0x87, 0x36,
    0xa0, 0x87, 0x70, 0x10, 0x07, 0x76, 0x28, 0x87, 0x79, 0x00, 0xcc, 0x21,
    0x1c, 0xd8, 0x61, 0x1e, 0xca, 0x01, 0x20, 0xdc, 0xe1, 0x1d, 0xda, 0xc0,
    0x1d, 0xc2, 0xc1, 0x1d, 0xe6, 0xa1, 0x0d, 0xcc, 0x01, 0x1e, 0xda, 0xa0,
    0x1d, 0xc2, 0x81, 0x1e, 0xd0, 0x01, 0xa0, 0x07, 0x79, 0xa8, 0x87, 0x72,
    0x00, 0x08, 0x77, 0x78, 0x87, 0x36, 0x98, 0x87, 0x74, 0x38, 0x07, 0x77,
    0x28, 0x07, 0x72, 0x68, 0x03, 0x7d, 0x28, 0x07, 0x79, 0x78, 0x87, 0x79,
    0x68, 0x03, 0x73, 0x80, 0x87, 0x36, 0x68, 0x87, 0x70, 0xa0, 0x07, 0x74,
    0x00, 0xe8, 0x41, 0x1e, 0xea, 0xa1, 0x1c, 0x00, 0xc2, 0x1d, 0xde, 0xa1,
    0x0d, 0xe8, 0x41, 0x1e, 0xc2, 0x01, 0x1e, 0xe0, 0x21, 0x1d, 0xdc, 0xe1,
    0x1c, 0xda, 0xa0, 0x1d, 0xc2, 0x81, 0x1e, 0xd0, 0x01, 0xa0, 0x07, 0x79,
    0xa8, 0x87, 0x72, 0x00, 0x88, 0x79, 0xa0, 0x87, 0x70, 0x18, 0x87, 0x75,
    0x68, 0x03, 0x78, 0x90, 0x87, 0x77, 0xa0, 0x87, 0x72, 0x18, 0x07, 0x7a,
    0x78, 0x07, 0x79, 0x68, 0x03, 0x71, 0xa8, 0x07, 0x73, 0x30, 0x87, 0x72,
    0x90, 0x87, 0x36, 0x98, 0x87, 0x74, 0xd0, 0x87, 0x72, 0x00, 0xf0, 0x00,
    0x20, 0xe8, 0x21, 0x1c, 0xe4, 0xe1, 0x1c, 0xca, 0x81, 0x1e, 0xda, 0xc0,
    0x1c, 0xca, 0x21, 0x1c, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe6, 0x01,
    0x68, 0x03, 0x73, 0x80, 0x87, 0x38, 0xb0, 0x03, 0x80, 0xa8, 0x07, 0x77,
    0x98, 0x87, 0x70, 0x30, 0x87, 0x72, 0x68, 0x03, 0x73, 0x80, 0x87, 0x36,
    0x68, 0x87, 0x70, 0xa0, 0x07, 0x74, 0x00, 0xe8, 0x41, 0x1e, 0xea, 0xa1,
    0x1c, 0x00, 0xa2, 0x1e, 0xe6, 0xa1, 0x1c, 0xda, 0x60, 0x1e, 0xde, 0xc1,
    0x1c, 0xe8, 0xa1, 0x0d, 0xcc, 0x81, 0x1d, 0xde, 0x21, 0x1c, 0xe8, 0x01,
    0x30, 0x87, 0x70, 0x60, 0x87, 0x79, 0x28, 0x07, 0x00, 0x00, 0x49, 0x18,
    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x82, 0x00, 0x00, 0x89, 0x20,
    0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64,
    0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1,
    0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x20,
    0x33, 0x00, 0xc3, 0x08, 0x04, 0x50, 0x86, 0x88, 0x20, 0x19, 0x08, 0x98,
    0x23, 0x00, 0x83, 0x39, 0x02, 0x50, 0x18, 0x01, 0x00, 0x00, 0x13, 0xb2,
    0x70, 0x48, 0x07, 0x79, 0xb0, 0x03, 0x3a, 0x68, 0x83, 0x70, 0x80, 0x07,
    0x78, 0x60, 0x87, 0x72, 0x68, 0x83, 0x76, 0x08, 0x87, 0x71, 0x78, 0x87,
    0x79, 0xc0, 0x87, 0x38, 0x80, 0x03, 0x37, 0x88, 0x03, 0x3a, 0x70, 0x03,
    0x38, 0xd8, 0xf0, 0x1e, 0xe5, 0xd0, 0x06, 0xf0, 0xa0, 0x07, 0x76, 0x40,
    0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x90,
    0x0e, 0x71, 0xa0, 0x07, 0x78, 0xa0, 0x07, 0x78, 0xd0, 0x06, 0xe9, 0x80,
    0x07, 0x7a, 0x80, 0x07, 0x7a, 0x80, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60,
    0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x6d, 0x90,
    0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20,
    0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0,
    0x07, 0x76, 0x40, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30,
    0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x76, 0x40,
    0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x60,
    0x0e, 0x78, 0x00, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10,
    0x07, 0x72, 0x80, 0x07, 0x6d, 0x60, 0x0f, 0x71, 0x60, 0x07, 0x7a, 0x10,
    0x07, 0x76, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x72, 0x40,
    0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60,
    0x0f, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20,
    0x07, 0x6d, 0x60, 0x0f, 0x74, 0x80, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xa0,
    0x07, 0x76, 0x40, 0x07, 0x6d, 0x60, 0x0f, 0x76, 0x40, 0x07, 0x7a, 0x60,
    0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x60, 0x0f, 0x79, 0x60,
    0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80,
    0x07, 0x6d, 0x60, 0x0f, 0x71, 0x20, 0x07, 0x78, 0xa0, 0x07, 0x71, 0x20,
    0x07, 0x78, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xf6, 0x10,
    0x07, 0x79, 0x20, 0x07, 0x7a, 0x20, 0x07, 0x75, 0x60, 0x07, 0x7a, 0x20,
    0x07, 0x75, 0x60, 0x07, 0x6d, 0x60, 0x0f, 0x72, 0x50, 0x07, 0x76, 0xa0,
    0x07, 0x72, 0x50, 0x07, 0x76, 0xa0, 0x07, 0x72, 0x50, 0x07, 0x76, 0xd0,
    0x06, 0xf6, 0x50, 0x07, 0x71, 0x20, 0x07, 0x7a, 0x50, 0x07, 0x71, 0x20,
    0x07, 0x7a, 0x50, 0x07, 0x71, 0x20, 0x07, 0x6d, 0x60, 0x0f, 0x71, 0x00,
    0x07, 0x72, 0x40, 0x07, 0x7a, 0x10, 0x07, 0x70, 0x20, 0x07, 0x74, 0xa0,
    0x07, 0x71, 0x00, 0x07, 0x72, 0x40, 0x07, 0x6d, 0x60, 0x0e, 0x78, 0x00,
    0x07, 0x7a, 0x10, 0x07, 0x72, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x72, 0x80,
    0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30,
    0x07, 0x72, 0xa0, 0x11, 0xc2, 0x90, 0x4e, 0x11, 0x01, 0x06, 0x43, 0x34,
    0x13, 0x7b, 0x00, 0x03, 0x11, 0x0d, 0x89, 0x00, 0x47, 0x00, 0x00, 0x20,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x89, 0x0d, 0x02, 0x45,
    0xb1, 0x04, 0x00, 0x00, 0xb2, 0x40, 0x06, 0x00, 0x00, 0x00, 0x32, 0x1e,
    0x98, 0x0c, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04,
    0x43, 0xaa, 0x12, 0x28, 0x84, 0x22, 0x18, 0x01, 0x00, 0x00, 0xb1, 0x18,
    0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1,
    0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42,
    0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f,
    0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1,
    0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84,
    0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc,
    0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70,
    0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19,
    0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f,
    0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21,
    0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc,
    0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84,
    0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37,
    0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70,
    0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77,
    0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79,
    0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e,
    0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1,
    0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81,
    0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98,
    0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88,
    0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4,
    0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc7, 0x69, 0x87, 0x70, 0x58, 0x87, 0x72,
    0x70, 0x83, 0x74, 0x68, 0x07, 0x78, 0x60, 0x87, 0x74, 0x18, 0x87, 0x74,
    0xa0, 0x87, 0x19, 0xce, 0x53, 0x0f, 0xee, 0x00, 0x0f, 0xf2, 0x50, 0x0e,
    0xe4, 0x90, 0x0e, 0xe3, 0x40, 0x0f, 0xe1, 0x20, 0x0e, 0xec, 0x50, 0x0e,
    0x33, 0x20, 0x28, 0x1d, 0xdc, 0xc1, 0x1e, 0xc2, 0x41, 0x1e, 0xd2, 0x21,
    0x1c, 0xdc, 0x81, 0x1e, 0xdc, 0xe0, 0x1c, 0xe4, 0xe1, 0x1d, 0xea, 0x01,
    0x1e, 0x66, 0x18, 0x51, 0x38, 0xb0, 0x43, 0x3a, 0x9c, 0x83, 0x3b, 0xcc,
    0x50, 0x24, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x60, 0x87, 0x77,
    0x78, 0x07, 0x78, 0x98, 0x51, 0x4c, 0xf4, 0x90, 0x0f, 0xf0, 0x50, 0x0e,
    0x33, 0x1e, 0x6a, 0x1e, 0xca, 0x61, 0x1c, 0xe8, 0x21, 0x1d, 0xde, 0xc1,
    0x1d, 0x7e, 0x01, 0x1e, 0xe4, 0xa1, 0x1c, 0xcc, 0x21, 0x1d, 0xf0, 0x61,
    0x06, 0x54, 0x85, 0x83, 0x38, 0xcc, 0xc3, 0x3b, 0xb0, 0x43, 0x3d, 0xd0,
    0x43, 0x39, 0xfc, 0xc2, 0x3c, 0xe4, 0x43, 0x3b, 0x88, 0xc3, 0x3b, 0xb0,
    0xc3, 0x8c, 0xc5, 0x0a, 0x87, 0x79, 0x98, 0x87, 0x77, 0x18, 0x87, 0x74,
    0x08, 0x07, 0x7a, 0x28, 0x07, 0x72, 0x00, 0x00, 0x00, 0x00, 0x79, 0x20,
    0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x62, 0x1e, 0x48, 0x20, 0x43, 0x88,
    0x0c, 0x19, 0x39, 0x19, 0x24, 0x90, 0x91, 0x40, 0xc6, 0xc8, 0xc8, 0x68,
    0x22, 0x50, 0x08, 0x14, 0x32, 0x9e, 0x18, 0x19, 0x21, 0x47, 0xc8, 0x90,
    0x51, 0x9c, 0x28, 0x7a, 0x01, 0x00, 0xca, 0x1a, 0x14, 0x1b, 0x57, 0x06,
    0x61, 0x10, 0x45, 0x06, 0xa3, 0x48, 0x4c, 0x24, 0x59, 0x4f, 0x01, 0x00,
    0x00, 0x00, 0x77, 0x63, 0x68, 0x61, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65,
    0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x4c, 0x4c, 0x56, 0x4d, 0x20, 0x76,
    0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x39, 0x30, 0x32, 0x2e, 0x31,
    0x20, 0x28, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x66, 0x65, 0x2d, 0x39, 0x30,
    0x32, 0x2e, 0x31, 0x2e, 0x34, 0x39, 0x29, 0x4d, 0x65, 0x74, 0x61, 0x6c,
    0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e,
    0x64, 0x65, 0x6e, 0x6f, 0x72, 0x6d, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61,
    0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69,
    0x6c, 0x65, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x68,
    0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e, 0x63,
    0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0x66, 0x72, 0x61, 0x6d, 0x65,
    0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68,
    0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e,
    0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0x6e, 0x61, 0x74, 0x69,
    0x76, 0x65, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69,
    0x73, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x69, 0x72, 0x2e, 0x72, 0x65, 0x6e,
    0x64, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x61, 0x69,
    0x72, 0x2e, 0x61, 0x72, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e,
    0x61, 0x6d, 0x65, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x61, 0x69, 0x72,
    0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x69, 0x72,
    0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x61, 0x69, 0x72, 0x2e, 0x6e,
    0x6f, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76,
    0x65, 0x61, 0x69, 0x72, 0x2e, 0x61, 0x72, 0x67, 0x5f, 0x6e, 0x61, 0x6d,
    0x65, 0x63, 0x6c, 0x69, 0x70, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6f,
    0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x69, 0x72, 0x2e, 0x66, 0x72,
    0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74,
    0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x28, 0x35, 0x63,
    0x6f, 0x6c, 0x6f, 0x72, 0x44, 0x76, 0x34, 0x5f, 0x66, 0x29, 0x61, 0x69,
    0x72, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76,
    0x65, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x23, 0x08, 0x45, 0x30, 0x82, 0x50,
    0x08, 0x23, 0x08, 0xc5, 0x30, 0x82, 0x50, 0x10, 0x23, 0x08, 0x03, 0x30,
    0xc3, 0x40, 0x05, 0xd5, 0x0c, 0x81, 0x30, 0xc3, 0x60, 0x51, 0xd7, 0x0c,
    0xc4, 0x60, 0x51, 0xd7, 0x0c, 0x01, 0x31, 0x43, 0x50, 0xcc, 0x10, 0x18,
    0x33, 0x04, 0xc7, 0x0c, 0x05, 0x72, 0x5d, 0x89, 0x32, 0x43, 0x10, 0x06,
    0x33, 0x20, 0xd7, 0xc2, 0x34, 0x89, 0xe2, 0x3c, 0x33, 0x24, 0x14, 0x14,
    0x31, 0x52, 0xa2, 0x38, 0xd3, 0x0c, 0xc2, 0x18, 0x90, 0xc1, 0x0c, 0x03,
    0x26, 0x06, 0x65, 0x20, 0x23, 0x81, 0x09, 0xca, 0x88, 0x8d, 0xcd, 0xae,
    0xcd, 0xa5, 0xed, 0x8d, 0xac, 0x8e, 0xad, 0xcc, 0xc5, 0x8c, 0x2d, 0xec,
    0x6c, 0x6e, 0x94, 0x00, 0x4b, 0x85, 0x8d, 0xcd, 0xae, 0xcd, 0x25, 0x8d,
    0xac, 0xcc, 0x8d, 0x6e, 0x94, 0x20, 0xcb, 0x25, 0x2c, 0x4d, 0xce, 0xc5,
    0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, 0x94, 0x40, 0x4b, 0x2a, 0x2c,
    0x4d, 0xce, 0x85, 0x2d, 0xcc, 0xed, 0xac, 0x2e, 0xec, 0xac, 0xec, 0xcb,
    0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, 0x94, 0x60, 0xcb, 0x29, 0x2c,
    0x4d, 0xce, 0x65, 0xec, 0xad, 0x0d, 0x2e, 0x8d, 0xad, 0xec, 0xeb, 0x0d,
    0x8e, 0x2e, 0xed, 0xcd, 0x6d, 0x6e, 0x14, 0x82, 0xeb, 0xbc, 0x2f, 0x99,
    0xb0, 0x34, 0x39, 0x17, 0x33, 0xb9, 0xb0, 0xb3, 0xb6, 0x32, 0x37, 0xba,
    0x51, 0x82, 0x32, 0x00, 0x00, 0x00, 0xa9, 0x18, 0x00, 0x00, 0x0b, 0x00,
    0x00, 0x00, 0x0b, 0x0a, 0x72, 0x28, 0x87, 0x77, 0x80, 0x07, 0x7a, 0x58,
    0x70, 0x98, 0x43, 0x3d, 0xb8, 0xc3, 0x38, 0xb0, 0x43, 0x39, 0xd0, 0xc3,
    0x82, 0xe6, 0x1c, 0xc6, 0xa1, 0x0d, 0xe8, 0x41, 0x1e, 0xc2, 0xc1, 0x1d,
    0xe6, 0x21, 0x1d, 0xe8, 0x21, 0x1d, 0xde, 0xc1, 0x1d, 0x00, 0xd1, 0x10,
    0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0xcc, 0x3c, 0xa4, 0x83, 0x3b,
    0x9c, 0x03, 0x3b, 0x94, 0x03, 0x3d, 0xa0, 0x83, 0x3c, 0x94, 0x43, 0x38,
    0x90, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x08, 0x00,
    0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
    0x00, 0x00, 0x64, 0x23, 0x00, 0x04, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf0,
    0x07, 0x00, 0x73, 0x0c, 0x43, 0x20, 0x64, 0x00, 0x00, 0x00, 0x71, 0x20,
    0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, 0x0e, 0x10, 0x22, 0x84, 0x00,
    0xce, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x0c,
    0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x12, 0x03, 0x94, 0xe8, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x08, 0x00,
    0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,
    0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
    0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
    0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x5d, 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x03,
    0x94, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65,
    0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x39, 0x30, 0x32, 0x2e,
    0x31, 0x2e, 0x34, 0x39, 0x61, 0x69, 0x72, 0x36, 0x34, 0x2d, 0x61, 0x70,
    0x70, 0x6c, 0x65, 0x2d, 0x6d, 0x61, 0x63, 0x6f, 0x73, 0x78, 0x31, 0x30,
    0x2e, 0x31, 0x34, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00};
}  // namespace

// There exists a 4-byte literal at this offset, which can be changed to any
// value in kValidLiteral to defeat caching.
const size_t kLiteralOffset = 0x167c;
const size_t kLiteralSize = 0x4;

namespace {
const uint8_t kValidLiteralValues[] = {
    0xef, 0x4c, 0x9a, 0x68, 0xef, 0x4c, 0x9a, 0x70, 0x66, 0x6f, 0xa6, 0x74,
    0xef, 0x4c, 0x9a, 0x78, 0x2a, 0x5e, 0x9f, 0x7a, 0x66, 0x6f, 0xa6, 0x7c,
    0xa2, 0x88, 0xab, 0x7e, 0xef, 0x4c, 0x9a, 0xa0, 0x7c, 0xd9, 0x9b, 0xa1,
    0x2a, 0x5e, 0x9f, 0xa2, 0xb8, 0xea, 0xa2, 0xa3, 0x66, 0x6f, 0xa6, 0xa4,
    0xf4, 0xfb, 0xa7, 0xa5, 0xa2, 0x88, 0xab, 0xa6, 0x2f, 0x0d, 0xaf, 0xa7,
    0xef, 0x4c, 0x9a, 0xa8, 0x36, 0x0f, 0xdb, 0xa8, 0x7c, 0xd9, 0x9b, 0xa9,
    0xe3, 0x9b, 0xde, 0xa9, 0x2a, 0x5e, 0x9f, 0xaa, 0x71, 0x28, 0xe2, 0xaa,
    0xb8, 0xea, 0xa2, 0xab, 0xff, 0xac, 0xe3, 0xab, 0x66, 0x6f, 0xa6, 0xac,
    0xad, 0x39, 0xe7, 0xac, 0xf4, 0xfb, 0xa7, 0xad, 0x3b, 0xbe, 0xea, 0xad,
    0xa2, 0x88, 0xab, 0xae, 0xe8, 0x4a, 0xee, 0xae, 0x2f, 0x0d, 0xaf, 0xaf,
    0x76, 0xcf, 0xef, 0xaf, 0x7c, 0xd9, 0x9b, 0xb1, 0xb0, 0x3a, 0xbe, 0xb1,
    0xe3, 0x9b, 0xde, 0xb1, 0xf7, 0xfc, 0xfe, 0xb1, 0x2a, 0x5e, 0x9f, 0xb2,
    0x3e, 0xbf, 0xbf, 0xb2, 0x71, 0x28, 0xe2, 0xb2, 0xb8, 0xea, 0xa2, 0xb3,
    0xec, 0x4b, 0xc3, 0xb3, 0xff, 0xac, 0xe3, 0xb3, 0x32, 0x0e, 0x86, 0xb4,
    0x66, 0x6f, 0xa6, 0xb4, 0x79, 0xd8, 0xc6, 0xb4, 0xad, 0x39, 0xe7, 0xb4,
    0xe0, 0x9a, 0x87, 0xb5, 0xf4, 0xfb, 0xa7, 0xb5, 0x27, 0x5d, 0xca, 0xb5,
    0x3b, 0xbe, 0xea, 0xb5, 0x6e, 0x1f, 0x8b, 0xb6, 0xa2, 0x88, 0xab, 0xb6,
    0xb5, 0xe9, 0xcb, 0xb6, 0xe8, 0x4a, 0xee, 0xb6, 0xfc, 0xab, 0x8e, 0xb7,
    0x2f, 0x0d, 0xaf, 0xb7, 0x63, 0x6e, 0xcf, 0xb7, 0x76, 0xcf, 0xef, 0xb7,
    0x65, 0x1c, 0x8a, 0xb8, 0xef, 0x4c, 0x9a, 0xb8, 0x78, 0x7d, 0xaa, 0xb8,
    0x22, 0xae, 0xba, 0xb8, 0xac, 0xde, 0xca, 0xb8, 0x36, 0x0f, 0xdb, 0xb8,
    0xbf, 0x3f, 0xeb, 0xb8, 0x69, 0x78, 0xfb, 0xb8, 0xf3, 0xa8, 0x8b, 0xb9,
    0x7c, 0xd9, 0x9b, 0xb9, 0x26, 0x0a, 0xae, 0xb9, 0xb0, 0x3a, 0xbe, 0xb9,
    0x3a, 0x6b, 0xce, 0xb9, 0xe3, 0x9b, 0xde, 0xb9, 0x6d, 0xcc, 0xee, 0xb9,
    0xf7, 0xfc, 0xfe, 0xb9, 0xa1, 0x2d, 0x8f, 0xba, 0x2a, 0x5e, 0x9f, 0xba,
    0xb4, 0x8e, 0xaf, 0xba, 0x3e, 0xbf, 0xbf, 0xba, 0xe7, 0xef, 0xcf, 0xba,
    0x71, 0x28, 0xe2, 0xba, 0xfb, 0x58, 0xf2, 0xba, 0x2e, 0xba, 0x92, 0xbb,
    0xb8, 0xea, 0xa2, 0xbb, 0x62, 0x1b, 0xb3, 0xbb, 0xec, 0x4b, 0xc3, 0xbb,
    0x75, 0x7c, 0xd3, 0xbb, 0xff, 0xac, 0xe3, 0xbb, 0xa9, 0xdd, 0xf3, 0xbb,
    0x32, 0x0e, 0x86, 0xbc, 0xbc, 0x3e, 0x96, 0xbc, 0x66, 0x6f, 0xa6, 0xbc,
    0xf0, 0x9f, 0xb6, 0xbc, 0x79, 0xd8, 0xc6, 0xbc, 0x23, 0x09, 0xd7, 0xbc,
    0xad, 0x39, 0xe7, 0xbc, 0x37, 0x6a, 0xf7, 0xbc, 0xe0, 0x9a, 0x87, 0xbd,
    0x6a, 0xcb, 0x97, 0xbd, 0xf4, 0xfb, 0xa7, 0xbd, 0x7d, 0x2c, 0xba, 0xbd,
    0x27, 0x5d, 0xca, 0xbd, 0xb1, 0x8d, 0xda, 0xbd, 0x3b, 0xbe, 0xea, 0xbd,
    0xe4, 0xee, 0xfa, 0xbd, 0x6e, 0x1f, 0x8b, 0xbe, 0xf8, 0x4f, 0x9b, 0xbe,
    0xa2, 0x88, 0xab, 0xbe, 0x2b, 0xb9, 0xbb, 0xbe, 0xb5, 0xe9, 0xcb, 0xbe,
    0x3f, 0x1a, 0xde, 0xbe, 0xe8, 0x4a, 0xee, 0xbe, 0x72, 0x7b, 0xfe, 0xbe,
    0xfc, 0xab, 0x8e, 0xbf, 0xa6, 0xdc, 0x9e, 0xbf, 0x2f, 0x0d, 0xaf, 0xbf,
    0xb9, 0x3d, 0xbf, 0xbf, 0x63, 0x6e, 0xcf, 0xbf, 0xed, 0x9e, 0xdf, 0xbf,
    0x76, 0xcf, 0xef, 0xbf, 0x65, 0x1c, 0x8a, 0xe0, 0xaa, 0x38, 0x92, 0xe0,
    0xef, 0x4c, 0x9a, 0xe0, 0x33, 0x69, 0xa2, 0xe0, 0x78, 0x7d, 0xaa, 0xe0,
    0xbd, 0x99, 0xb2, 0xe0, 0x22, 0xae, 0xba, 0xe0, 0x67, 0xca, 0xc2, 0xe0,
    0xac, 0xde, 0xca, 0xe0, 0xf1, 0xfa, 0xd2, 0xe0, 0x36, 0x0f, 0xdb, 0xe0,
    0x7a, 0x2b, 0xe3, 0xe0, 0xbf, 0x3f, 0xeb, 0xe0, 0x24, 0x5c, 0xf3, 0xe0,
    0x69, 0x78, 0xfb, 0xe0, 0xae, 0x8c, 0x83, 0xe1, 0xf3, 0xa8, 0x8b, 0xe1,
    0x38, 0xbd, 0x93, 0xe1, 0x7c, 0xd9, 0x9b, 0xe1, 0xe1, 0xed, 0xa3, 0xe1,
    0x26, 0x0a, 0xae, 0xe1, 0x6b, 0x1e, 0xb6, 0xe1, 0xb0, 0x3a, 0xbe, 0xe1,
    0xf5, 0x4e, 0xc6, 0xe1, 0x3a, 0x6b, 0xce, 0xe1, 0x7e, 0x7f, 0xd6, 0xe1,
    0xe3, 0x9b, 0xde, 0xe1, 0x28, 0xb8, 0xe6, 0xe1, 0x6d, 0xcc, 0xee, 0xe1,
    0xb2, 0xe8, 0xf6, 0xe1, 0xf7, 0xfc, 0xfe, 0xe1, 0x3c, 0x19, 0x87, 0xe2,
    0xa1, 0x2d, 0x8f, 0xe2, 0xe5, 0x49, 0x97, 0xe2, 0x2a, 0x5e, 0x9f, 0xe2,
    0x6f, 0x7a, 0xa7, 0xe2, 0xb4, 0x8e, 0xaf, 0xe2, 0xf9, 0xaa, 0xb7, 0xe2,
    0x3e, 0xbf, 0xbf, 0xe2, 0xa3, 0xdb, 0xc7, 0xe2, 0xe7, 0xef, 0xcf, 0xe2,
    0x2c, 0x0c, 0xda, 0xe2, 0x71, 0x28, 0xe2, 0xe2, 0xb6, 0x3c, 0xea, 0xe2,
    0xfb, 0x58, 0xf2, 0xe2, 0x60, 0x6d, 0xfa, 0xe2, 0xe9, 0x9d, 0x8a, 0xe3,
    0x2e, 0xba, 0x92, 0xe3, 0x73, 0xce, 0x9a, 0xe3, 0xb8, 0xea, 0xa2, 0xe3,
    0xfd, 0xfe, 0xaa, 0xe3, 0x62, 0x1b, 0xb3, 0xe3, 0xa7, 0x2f, 0xbb, 0xe3,
    0xec, 0x4b, 0xc3, 0xe3, 0x30, 0x68, 0xcb, 0xe3, 0x75, 0x7c, 0xd3, 0xe3,
    0xba, 0x98, 0xdb, 0xe3, 0xff, 0xac, 0xe3, 0xe3, 0x64, 0xc9, 0xeb, 0xe3,
    0xa9, 0xdd, 0xf3, 0xe3, 0xee, 0xf9, 0xfb, 0xe3, 0x32, 0x0e, 0x86, 0xe4,
    0x77, 0x2a, 0x8e, 0xe4, 0xbc, 0x3e, 0x96, 0xe4, 0x21, 0x5b, 0x9e, 0xe4,
    0x66, 0x6f, 0xa6, 0xe4, 0xab, 0x8b, 0xae, 0xe4, 0xf0, 0x9f, 0xb6, 0xe4,
    0x34, 0xbc, 0xbe, 0xe4, 0x79, 0xd8, 0xc6, 0xe4, 0xbe, 0xec, 0xce, 0xe4,
    0x23, 0x09, 0xd7, 0xe4, 0x68, 0x1d, 0xdf, 0xe4, 0xad, 0x39, 0xe7, 0xe4,
    0xf2, 0x4d, 0xef, 0xe4, 0x37, 0x6a, 0xf7, 0xe4, 0x7b, 0x7e, 0xff, 0xe4,
    0xe0, 0x9a, 0x87, 0xe5, 0x25, 0xaf, 0x8f, 0xe5, 0x6a, 0xcb, 0x97, 0xe5,
    0xaf, 0xdf, 0x9f, 0xe5, 0xf4, 0xfb, 0xa7, 0xe5, 0x39, 0x18, 0xb2, 0xe5,
    0x7d, 0x2c, 0xba, 0xe5, 0xe2, 0x48, 0xc2, 0xe5, 0x27, 0x5d, 0xca, 0xe5,
    0x6c, 0x79, 0xd2, 0xe5, 0xb1, 0x8d, 0xda, 0xe5, 0xf6, 0xa9, 0xe2, 0xe5,
    0x3b, 0xbe, 0xea, 0xe5, 0x7f, 0xda, 0xf2, 0xe5, 0xe4, 0xee, 0xfa, 0xe5,
    0x29, 0x0b, 0x83, 0xe6, 0x6e, 0x1f, 0x8b, 0xe6, 0xb3, 0x3b, 0x93, 0xe6,
    0xf8, 0x4f, 0x9b, 0xe6, 0x3d, 0x6c, 0xa3, 0xe6, 0xa2, 0x88, 0xab, 0xe6,
    0xe6, 0x9c, 0xb3, 0xe6, 0x2b, 0xb9, 0xbb, 0xe6, 0x70, 0xcd, 0xc3, 0xe6,
    0xb5, 0xe9, 0xcb, 0xe6, 0xfa, 0xfd, 0xd3, 0xe6, 0x3f, 0x1a, 0xde, 0xe6,
    0xa4, 0x2e, 0xe6, 0xe6, 0xe8, 0x4a, 0xee, 0xe6, 0x2d, 0x5f, 0xf6, 0xe6,
    0x72, 0x7b, 0xfe, 0xe6, 0xb7, 0x8f, 0x86, 0xe7, 0xfc, 0xab, 0x8e, 0xe7,
    0x61, 0xc8, 0x96, 0xe7, 0xa6, 0xdc, 0x9e, 0xe7, 0xea, 0xf8, 0xa6, 0xe7,
    0x2f, 0x0d, 0xaf, 0xe7, 0x74, 0x29, 0xb7, 0xe7, 0xb9, 0x3d, 0xbf, 0xe7,
    0xfe, 0x59, 0xc7, 0xe7, 0x63, 0x6e, 0xcf, 0xe7, 0xa8, 0x8a, 0xd7, 0xe7,
    0xed, 0x9e, 0xdf, 0xe7, 0x31, 0xbb, 0xe7, 0xe7, 0x76, 0xcf, 0xef, 0xe7,
    0xbb, 0xeb, 0xf7, 0xe7, 0x32, 0x0e, 0x86, 0xe8, 0x65, 0x1c, 0x8a, 0xe8,
    0x77, 0x2a, 0x8e, 0xe8, 0xaa, 0x38, 0x92, 0xe8, 0xbc, 0x3e, 0x96, 0xe8,
    0xef, 0x4c, 0x9a, 0xe8, 0x21, 0x5b, 0x9e, 0xe8, 0x33, 0x69, 0xa2, 0xe8,
    0x66, 0x6f, 0xa6, 0xe8, 0x78, 0x7d, 0xaa, 0xe8, 0xab, 0x8b, 0xae, 0xe8,
    0xbd, 0x99, 0xb2, 0xe8, 0xf0, 0x9f, 0xb6, 0xe8, 0x22, 0xae, 0xba, 0xe8,
};

// The sha256 hash of the bitcode is stored at this offset in the shader.
const size_t kTestLibHashOffset = 0x104;

// The bitcode that is hashed is stored at this offset and with this size.
const size_t kTestLibBitcodeOffset = 0xd16;
const size_t kTestLibBitcodeSize = 0xa50;

crash_reporter::CrashKeyString<32>& GetLinkIndexCrashKey() {
  static crash_reporter::CrashKeyString<32> crash_key("metal-link-index");
  return crash_key;
}

}  // namespace

std::vector<uint8_t> GetAlteredLibraryData() {
  // Make a copy of the shader's data.
  std::vector<uint8_t> data(kTestLibData, kTestLibData + kTestLibSize);

  // Alter the data at kLiteralOffset to defeat caching.
  uint64_t index =
      base::RandInt(0, sizeof(kValidLiteralValues) / kLiteralSize - 1);
  for (size_t i = 0; i < kLiteralSize; ++i)
    data[kLiteralOffset + i] = kValidLiteralValues[kLiteralSize * index + i];

  // Compute the hash of the altered bitcode and and place it in the data.
  CC_SHA256(&data[kTestLibBitcodeOffset], kTestLibBitcodeSize,
            &data[kTestLibHashOffset]);

  // Shader link crashes have been observed on bots. Record what index caused
  // them if they appear in the wild.
  GetLinkIndexCrashKey().Set(base::StringPrintf("%llu", index));
  return data;
}

namespace {

base::ScopedDispatchObject<dispatch_data_t> GetLibraryData() {
  auto vector_data = GetAlteredLibraryData();
  base::ScopedDispatchObject<dispatch_data_t> dispatch_data(
      dispatch_data_create(vector_data.data(), vector_data.size(), nullptr,
                           DISPATCH_DATA_DESTRUCTOR_DEFAULT));
  return dispatch_data;
}

// State shared between the compiler callback and the caller.
class TestShaderState : public base::RefCountedThreadSafe<TestShaderState> {
 public:
  TestShaderState(TestShaderCallback callback,
                  TestShaderComponent component,
                  const base::TimeDelta& timeout)
      : callback_(std::move(callback)),
        component_(component),
        timeout_(timeout),
        start_time_(base::TimeTicks::Now()) {}

  // Called when the completion callback happens.
  void OnCompletionHandlerCalled(TestShaderResult result) {
    {
      base::AutoLock lock(lock_);
      result_ = result;
      completion_handler_called_time_ = base::TimeTicks::Now();
    }
    RunCallbackIfReady();
  }

  // Called when the call to newLibraryWithSource or
  // newRenderStateWithDescriptor completes. Note that this may happen before or
  // after OnCompletionHandlerCalled is called.
  void OnMethodCompleted() {
    {
      base::AutoLock lock(lock_);
      method_completed_time_ = base::TimeTicks::Now();
    }
    RunCallbackIfReady();
  }

  // Called on timeout. This is always called eventually.
  void OnTimeout() {
    {
      base::AutoLock lock(lock_);
      timed_out_ = true;
    }
    RunCallbackIfReady();
  }

 protected:
  virtual ~TestShaderState() = default;
  void RunCallbackIfReady() {
    base::OnceClosure closure;
    {
      base::AutoLock lock(lock_);
      // Early-out if we have already run the callback.
      if (!callback_)
        return;

      // We're ready to run the callback if we have timed out, or if both times
      // have been set.
      if (!timed_out_ && (method_completed_time_.is_null() ||
                          completion_handler_called_time_.is_null()))
        return;

      // It would be truly bizarre to have newLibraryWithSource hang, but yet
      // have the completion handler have been called. Crash if we see this,
      // rather than trying to reason about it.
      if (method_completed_time_.is_null())
        CHECK(completion_handler_called_time_.is_null());

      // We will use a single histogram for both "how long did compile take" and
      // "did compile complete in 1 minute" by pushing timeouts into the maximum
      // bucket of UMA_HISTOGRAM_MEDIUM_TIMES.
      base::TimeDelta method_time = kTestShaderTimeForever;
      if (!method_completed_time_.is_null())
        method_time = std::min(timeout_, method_completed_time_ - start_time_);
      base::TimeDelta compile_time = kTestShaderTimeForever;
      if (!completion_handler_called_time_.is_null())
        compile_time =
            std::min(timeout_, completion_handler_called_time_ - start_time_);

      // Set up the callback to execute once we release the lock.
      closure = base::BindOnce(std::move(callback_), component_, result_,
                               compile_time);
    }
    if (closure) {
      // If this is a link that has completed, then we set the crash key when
      // constructing the shader binary. Clear it now, because Metal didn't
      // crash while linking the shader.
      if (component_ == TestShaderComponent::kLink)
        GetLinkIndexCrashKey().Clear();
      std::move(closure).Run();
    }
  }

  base::Lock lock_;
  TestShaderCallback callback_;
  TestShaderResult result_ = TestShaderResult::kTimedOut;
  const TestShaderComponent component_;
  const base::TimeDelta timeout_;
  const base::TimeTicks start_time_;
  base::TimeTicks method_completed_time_;
  base::TimeTicks completion_handler_called_time_;
  bool timed_out_ = false;

  friend class base::RefCountedThreadSafe<TestShaderState>;
};

void TestRenderPipelineStateNow(base::scoped_nsprotocol<id<MTLDevice>> device,
                                const base::TimeDelta& timeout,
                                TestShaderCallback callback)
    API_AVAILABLE(macos(10.14)) {
  // Load the library binary. This should not fail.
  base::ScopedDispatchObject<dispatch_data_t> library_data = GetLibraryData();
  NSError* error = nil;
  base::scoped_nsprotocol<id<MTLLibrary>> library(
      [device newLibraryWithData:library_data error:&error]);
  base::scoped_nsprotocol<id<MTLFunction>> vertex_fn(
      [library newFunctionWithName:@"vertexShader"]);
  base::scoped_nsprotocol<id<MTLFunction>> fragment_fn(
      [library newFunctionWithName:@"fragmentShader"]);
  if (error || !library || !vertex_fn || !fragment_fn)
    return;

  // Initialize the TestShaderState and post the timeout callback, before
  // calling into the Metal API.
  auto state = base::MakeRefCounted<TestShaderState>(
      std::move(callback), TestShaderComponent::kLink, timeout);
  base::ThreadPool::PostDelayedTask(
      FROM_HERE, {}, base::BindOnce(&TestShaderState::OnTimeout, state),
      timeout);

  // Request asynchronous compile of the RenderPipelineState.
  base::scoped_nsobject<MTLRenderPipelineDescriptor> descriptor(
      [[MTLRenderPipelineDescriptor alloc] init]);
  [descriptor setLabel:@"Test Pipeline"];
  [descriptor setVertexFunction:vertex_fn];
  [descriptor setFragmentFunction:fragment_fn];
  [descriptor colorAttachments][0].pixelFormat = MTLPixelFormatBGRA8Unorm;
  MTLNewRenderPipelineStateCompletionHandler completion_handler =
      ^(id<MTLRenderPipelineState> render_pipeline_state, NSError* ns_error) {
        state->OnCompletionHandlerCalled(render_pipeline_state
                                             ? TestShaderResult::kSucceeded
                                             : TestShaderResult::kFailed);
      };
  [device newRenderPipelineStateWithDescriptor:descriptor
                             completionHandler:completion_handler];

  state->OnMethodCompleted();
}

void TestShaderNow(base::scoped_nsprotocol<id<MTLDevice>> device,
                   const base::TimeDelta& timeout,
                   TestShaderCallback callback) API_AVAILABLE(macos(10.14)) {
  // Initialize the TestShaderState and post the timeout callback, before
  // calling into the Metal API.
  auto state = base::MakeRefCounted<TestShaderState>(
      std::move(callback), TestShaderComponent::kCompile, timeout);
  base::ThreadPool::PostDelayedTask(
      FROM_HERE, {}, base::BindOnce(&TestShaderState::OnTimeout, state),
      timeout);

  const std::string shader_source =
      base::StringPrintf(kTestShaderSource, base::RandDouble());
  base::scoped_nsobject<NSString> source([[NSString alloc]
      initWithCString:shader_source.c_str()
             encoding:NSASCIIStringEncoding]);
  base::scoped_nsobject<MTLCompileOptions> options(
      [[MTLCompileOptions alloc] init]);
  MTLNewLibraryCompletionHandler completion_handler =
      ^(id<MTLLibrary> library, NSError* error) {
        state->OnCompletionHandlerCalled(library ? TestShaderResult::kSucceeded
                                                 : TestShaderResult::kFailed);
      };
  [device newLibraryWithSource:source
                       options:options
             completionHandler:completion_handler];
  state->OnMethodCompleted();
}

}  // namespace

void TestShader(TestShaderCallback callback,
                const base::TimeDelta& delay,
                const base::TimeDelta& timeout) {
  if (!base::FeatureList::IsEnabled(kMetalTestShaders))
    return;

  // Select a component to test at random.
  TestShaderComponent component = base::RandInt(0, 1)
                                      ? TestShaderComponent::kLink
                                      : TestShaderComponent::kCompile;

  // The metallib listed above is in MTLLanguageVersion2_1, which is available
  // only on 10.14 and above.
  if (@available(macOS 10.14, *)) {
    base::scoped_nsprotocol<id<MTLDevice>> device(CreateDefaultDevice());
    if (device) {
      // Select the callback depending on if we're testing online or offline
      // compile.
      base::OnceClosure closure;
      switch (component) {
        case TestShaderComponent::kCompile:
          closure = base::BindOnce(&TestShaderNow, device, timeout,
                                   std::move(callback));
          break;
        case TestShaderComponent::kLink:
          closure = base::BindOnce(&TestRenderPipelineStateNow, device, timeout,
                                   std::move(callback));
          break;
      }
      if (closure) {
        base::ThreadPool::PostDelayedTask(FROM_HERE,
                                          {base::TaskPriority::HIGHEST},
                                          std::move(closure), delay);
        return;
      }
    }
  }
  std::move(callback).Run(component, TestShaderResult::kNotAttempted,
                          base::TimeDelta());
}

}  // namespace metal
